home *** CD-ROM | disk | FTP | other *** search
/ Delphi Informant Complete 1995 - 2000 / Delphi Informant Complete 1995 to 2000.iso / Delphi Informant Magazine Complete Works SOURCE CODE 1998.rar / 1998 / Nov / di9811gd / Example2 / Unit1.pas < prev    next >
Pascal/Delphi Source File  |  1998-04-25  |  6KB  |  215 lines

  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls;
  8.  
  9. type
  10.   { TLightThread }
  11.   {* For easy management of threads.                                          *}
  12.   {* Allows a thread to be "created" with a passed thread function. The       *}
  13.   {* function will exit cleanly when ThreadExiting is set to true, or         *}
  14.   {* "nastily" after a timeout of ThreadExitTimeout milliseconds.             *}
  15.   {* For the purposes of this example, though, we are pretty assured that the *}
  16.   {* ThreadFunc used will always exit cleanly... (How else to demonstrate     *}
  17.   {* a thread-safe DLL?)                                                      *}
  18.   TLightThread = class(TObject)
  19.   protected
  20.     FThreadHandle: THandle;
  21.     FThreadID: DWord;
  22.     FCS: TRTLCriticalSection;
  23.     FThreadExiting: Boolean;
  24.     function GetThreadExiting: Boolean;
  25.   public
  26.     constructor Create(ThreadFunc: TThreadFunc);
  27.     destructor Destroy; override;
  28.     property ThreadExiting: Boolean read GetThreadExiting;
  29.     property ThreadHandle: THandle read FThreadHandle;
  30.     property ThreadID: DWord read FThreadID;
  31.   end;
  32.  
  33.   { TForm1 }
  34.   TForm1 = class(TForm)
  35.     btnLoad: TButton;
  36.     btnUnload: TButton;
  37.     lbThreads: TListBox;
  38.     Label1: TLabel;
  39.     btnNewThread: TButton;
  40.     btnCloseThread: TButton;
  41.     procedure FormCreate(Sender: TObject);
  42.     procedure FormDestroy(Sender: TObject);
  43.     procedure btnLoadClick(Sender: TObject);
  44.     procedure btnUnloadClick(Sender: TObject);
  45.     procedure btnNewThreadClick(Sender: TObject);
  46.     procedure btnCloseThreadClick(Sender: TObject);
  47.   private
  48.     { Private declarations }
  49.   public
  50.     { Public declarations }
  51.     LibHandle: THandle;
  52.     ThreadList: TList;
  53.     procedure FreeLib;
  54.     procedure NewThread;
  55.     procedure CloseThread(Idx: Integer); { Close indexed thread. }
  56.     procedure CloseThreads;
  57.   end;
  58.  
  59. var
  60.   Form1: TForm1;
  61.  
  62. const
  63.   ThreadSleepLength = 50; // 50 ms.
  64.   ThreadExitTimeout = 10000;
  65.  
  66. implementation
  67.  
  68. {$R *.DFM}
  69.  
  70. function ThreadFunc(Parameter: Pointer): Integer;
  71. begin
  72.   while (not TLightThread(Parameter).ThreadExiting) do
  73.     Sleep(ThreadSleepLength);
  74.   result := 0;
  75. end;
  76.  
  77. { TLightThread }
  78. constructor TLightThread.Create(ThreadFunc: TThreadFunc);
  79. begin
  80.   InitializeCriticalSection(FCS);
  81.   FThreadExiting := False;
  82.   try
  83.     FThreadHandle :=
  84.       BeginThread(nil, 0, ThreadFunc, Pointer(Self), 0, FThreadID);
  85.   except
  86.     on E: Exception do begin
  87.       DeleteCriticalSection(FCS);
  88.       raise;
  89.     end;
  90.   end;
  91. end;
  92.  
  93. destructor TLightThread.Destroy;
  94. begin
  95.   EnterCriticalSection(FCS);
  96.   try
  97.     FThreadExiting := True;
  98.   finally
  99.     LeaveCriticalSection(FCS);
  100.   end;
  101.   WaitForSingleObject(FThreadHandle, ThreadExitTimeout);
  102.   CloseHandle(FThreadHandle);
  103.   DeleteCriticalSection(FCS);
  104.   inherited;
  105. end;
  106.  
  107. function TLightThread.GetThreadExiting: Boolean;
  108. begin
  109.   EnterCriticalSection(FCS);
  110.   try
  111.     result := FThreadExiting;
  112.   finally
  113.     LeaveCriticalSection(FCS);
  114.   end;
  115. end;
  116.  
  117.  
  118. { TForm1 }
  119.  
  120. procedure TForm1.FormCreate(Sender: TObject);
  121. begin
  122.   IsMultiThread := True;
  123.   LibHandle := 0;
  124.   ThreadList := TList.Create;
  125. end;
  126.  
  127. procedure TForm1.FormDestroy(Sender: TObject);
  128. begin
  129.   FreeLib;                           // Free the library, if necessary
  130.   CloseThreads;                      // Guarantee that threads are closed.
  131.   ThreadList.Free;                   // Free the list of threads.
  132. end;
  133.  
  134. procedure TForm1.btnLoadClick(Sender: TObject);
  135. begin
  136.   if LibHandle = 0 then
  137.     LibHandle := LoadLibrary('Dll2.dll');
  138. end;
  139.  
  140. procedure TForm1.btnUnloadClick(Sender: TObject);
  141. begin
  142.   FreeLib;                           // Free the library, if necessary
  143. end;
  144.  
  145. procedure TForm1.btnNewThreadClick(Sender: TObject);
  146. begin
  147.   NewThread;
  148. end;
  149.  
  150. procedure TForm1.btnCloseThreadClick(Sender: TObject);
  151. begin
  152.   CloseThread(lbThreads.ItemIndex);
  153. end;
  154.  
  155. procedure TForm1.FreeLib;
  156. var
  157.   i, Cnt: Integer;
  158. begin
  159.   {* In comments is the appropriate way for a calling application
  160.      to free its library when it has multiple threads; however, for
  161.      the purpose of the example, we _just_ unload the library *}
  162.   FreeLibrary(LibHandle);
  163.   LibHandle := 0;
  164.   {if LibHandle <> 0 then begin
  165.     try
  166.       Cnt := ThreadList.Count;
  167.       for i := 0 to Cnt - 1 do CloseThread(0);
  168.       FreeLibrary(LibHandle);
  169.     finally
  170.       LibHandle := 0;
  171.     end;
  172.   end;}
  173. end;
  174.  
  175. procedure TForm1.NewThread;
  176. var
  177.   Thd: TLightThread;
  178. begin
  179.   { Create a thread }
  180.   Thd := TLightThread.Create(ThreadFunc);
  181.   { If thread was created successfully, then add the thread handle to
  182.     ThreadList, increment thread count and add an "identifier" to
  183.     the ListBox (for identification purposes only). }
  184.   ThreadList.Add(Pointer(Thd));
  185.   lbThreads.Items.Add('Thread #' + IntToStr(Thd.ThreadHandle));
  186.   lbThreads.ItemIndex := lbThreads.Items.Count - 1;
  187. end;
  188.  
  189. procedure TForm1.CloseThread(Idx: Integer);
  190. begin
  191.   if (Idx >= 0) and (Idx < ThreadList.Count) then begin
  192.     TLightThread(ThreadList.Items[Idx]).Free;
  193.     ThreadList.Delete(Idx);  ThreadList.Pack;
  194.     lbThreads.Items.Delete(Idx);
  195.     if (Idx = ThreadList.Count) then
  196.       lbThreads.ItemIndex := Idx - 1
  197.     else
  198.       lbThreads.ItemIndex := Idx;
  199.   end;
  200. end;
  201.  
  202. procedure TForm1.CloseThreads;
  203. var
  204.   i, Cnt: Integer;
  205. begin
  206.   Cnt := ThreadList.Count;
  207.   for i := 0 to Cnt - 1 do CloseThread(0);
  208. end;
  209.  
  210. initialization
  211.  
  212.   IsMultiThread := True;
  213.  
  214. end.
  215.